home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / groff_src.lha / Groff-1.07 / refer / label.cc < prev    next >
C/C++ Source or Header  |  1992-10-01  |  51KB  |  1,965 lines

  1.  
  2. /*  A Bison parser, made from label.y  */
  3.  
  4. #define YYBISON 1  /* Identify Bison output.  */
  5.  
  6. #define    TOKEN_LETTER    258
  7. #define    TOKEN_LITERAL    259
  8. #define    TOKEN_DIGIT    260
  9.  
  10. #line 21 "label.y"
  11.  
  12.  
  13. #include "refer.h"
  14. #include "refid.h"
  15. #include "ref.h"
  16. #include "token.h"
  17.  
  18. int yylex();
  19. void yyerror(const char *);
  20. int yyparse();
  21.  
  22. static const char *format_serial(char c, int n);
  23.  
  24. struct label_info {
  25.   int start;
  26.   int length;
  27.   int count;
  28.   int total;
  29.   label_info(const string &);
  30. };
  31.  
  32. label_info *lookup_label(const string &label);
  33.  
  34. struct expression {
  35.   enum {
  36.     // Does the tentative label depend on the reference?
  37.     CONTAINS_VARIABLE = 01, 
  38.     CONTAINS_STAR = 02,
  39.     CONTAINS_FORMAT = 04,
  40.     CONTAINS_AT = 010
  41.   };
  42.   virtual ~expression() { }
  43.   virtual void evaluate(int, const reference &, string &,
  44.             substring_position &) = 0;
  45.   virtual unsigned analyze() { return 0; }
  46. };
  47.  
  48. class at_expr : public expression {
  49. public:
  50.   at_expr() { }
  51.   void evaluate(int, const reference &, string &, substring_position &);
  52.   unsigned analyze() { return CONTAINS_VARIABLE|CONTAINS_AT; }
  53. };
  54.  
  55. class format_expr : public expression {
  56.   char type;
  57.   int width;
  58.   int first_number;
  59. public:
  60.   format_expr(char c, int w = 0, int f = 1)
  61.     : type(c), width(w), first_number(f) { }
  62.   void evaluate(int, const reference &, string &, substring_position &);
  63.   unsigned analyze() { return CONTAINS_FORMAT; }
  64. };
  65.  
  66. class field_expr : public expression {
  67.   int number;
  68.   char name;
  69. public:
  70.   field_expr(char nm, int num) : name(nm), number(num) { }
  71.   void evaluate(int, const reference &, string &, substring_position &);
  72.   unsigned analyze() { return CONTAINS_VARIABLE; }
  73. };
  74.  
  75. class literal_expr : public expression {
  76.   string s;
  77. public:
  78.   literal_expr(const char *ptr, int len) : s(ptr, len) { }
  79.   void evaluate(int, const reference &, string &, substring_position &);
  80. };
  81.  
  82. class unary_expr : public expression {
  83. protected:
  84.   expression *expr;
  85. public:
  86.   unary_expr(expression *e) : expr(e) { }
  87.   ~unary_expr() { delete expr; }
  88.   void evaluate(int, const reference &, string &, substring_position &) = 0;
  89.   unsigned analyze() { return expr ? expr->analyze() : 0; }
  90. };
  91.  
  92. // This caches the analysis of an expression.
  93.  
  94. class analyzed_expr : public unary_expr {
  95.   unsigned flags;
  96. public:
  97.   analyzed_expr(expression *);
  98.   void evaluate(int, const reference &, string &, substring_position &);
  99.   unsigned analyze() { return flags; }
  100. };
  101.  
  102. class star_expr : public unary_expr {
  103. public:
  104.   star_expr(expression *e) : unary_expr(e) { }
  105.   void evaluate(int, const reference &, string &, substring_position &);
  106.   unsigned analyze() {
  107.     return ((expr ? (expr->analyze() & ~CONTAINS_VARIABLE) : 0)
  108.         | CONTAINS_STAR);
  109.   }
  110. };
  111.  
  112. typedef void map_t(const char *, const char *, string &);
  113.  
  114. class map_expr : public unary_expr {
  115.   map_t *func;
  116. public:
  117.   map_expr(expression *e, map_t *f) : unary_expr(e), func(f) { }
  118.   void evaluate(int, const reference &, string &, substring_position &);
  119. };
  120.   
  121. typedef const char *extractor_t(const char *, const char *, const char **);
  122.  
  123. class extractor_expr : public unary_expr {
  124.   int part;
  125.   extractor_t *func;
  126. public:
  127.   enum { BEFORE = +1, MATCH = 0, AFTER = -1 };
  128.   extractor_expr(expression *e, extractor_t *f, int pt)
  129.     : unary_expr(e), func(f), part(pt) { }
  130.   void evaluate(int, const reference &, string &, substring_position &);
  131. };
  132.  
  133. class truncate_expr : public unary_expr {
  134.   int n;
  135. public:
  136.   truncate_expr(expression *e, int i) : n(i), unary_expr(e) { } 
  137.   void evaluate(int, const reference &, string &, substring_position &);
  138. };
  139.  
  140. class separator_expr : public unary_expr {
  141. public:
  142.   separator_expr(expression *e) : unary_expr(e) { }
  143.   void evaluate(int, const reference &, string &, substring_position &);
  144. };
  145.  
  146. class binary_expr : public expression {
  147. protected:
  148.   expression *expr1;
  149.   expression *expr2;
  150. public:
  151.   binary_expr(expression *e1, expression *e2) : expr1(e1), expr2(e2) { }
  152.   ~binary_expr() { delete expr1; delete expr2; }
  153.   void evaluate(int, const reference &, string &, substring_position &) = 0;
  154.   unsigned analyze() {
  155.     return (expr1 ? expr1->analyze() : 0) | (expr2 ? expr2->analyze() : 0);
  156.   }
  157. };
  158.  
  159. class alternative_expr : public binary_expr {
  160. public:
  161.   alternative_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
  162.   void evaluate(int, const reference &, string &, substring_position &);
  163. };
  164.  
  165. class list_expr : public binary_expr {
  166. public:
  167.   list_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
  168.   void evaluate(int, const reference &, string &, substring_position &);
  169. };
  170.  
  171. class substitute_expr : public binary_expr {
  172. public:
  173.   substitute_expr(expression *e1, expression *e2) : binary_expr(e1, e2) { }
  174.   void evaluate(int, const reference &, string &, substring_position &);
  175. };
  176.  
  177. class ternary_expr : public expression {
  178. protected:
  179.   expression *expr1;
  180.   expression *expr2;
  181.   expression *expr3;
  182. public:
  183.   ternary_expr(expression *e1, expression *e2, expression *e3)
  184.     : expr1(e1), expr2(e2), expr3(e3) { }
  185.   ~ternary_expr() { delete expr1; delete expr2; delete expr3; }
  186.   void evaluate(int, const reference &, string &, substring_position &) = 0;
  187.   unsigned analyze() {
  188.     return ((expr1 ? expr1->analyze() : 0)
  189.         | (expr2 ? expr2->analyze() : 0)
  190.         | (expr3 ? expr3->analyze() : 0));
  191.   }
  192. };
  193.  
  194. class conditional_expr : public ternary_expr {
  195. public:
  196.   conditional_expr(expression *e1, expression *e2, expression *e3)
  197.     : ternary_expr(e1, e2, e3) { }
  198.   void evaluate(int, const reference &, string &, substring_position &);
  199. };
  200.  
  201. static expression *parsed_label = 0;
  202. static expression *parsed_date_label = 0;
  203. static expression *parsed_short_label = 0;
  204.  
  205. static expression *parse_result;
  206.  
  207. string literals;
  208.  
  209.  
  210. #line 221 "label.y"
  211. typedef union {
  212.   int num;
  213.   expression *expr;
  214.   struct { int ndigits; int val; } dig;
  215.   struct { int start; int len; } str;
  216. } YYSTYPE;
  217.  
  218. #ifndef YYLTYPE
  219. typedef
  220.   struct yyltype
  221.     {
  222.       int timestamp;
  223.       int first_line;
  224.       int first_column;
  225.       int last_line;
  226.       int last_column;
  227.       char *text;
  228.    }
  229.   yyltype;
  230.  
  231. #define YYLTYPE yyltype
  232. #endif
  233.  
  234. #include <stdio.h>
  235.  
  236. #ifndef __STDC__
  237. #define const
  238. #endif
  239.  
  240.  
  241.  
  242. #define    YYFINAL        49
  243. #define    YYFLAG        -32768
  244. #define    YYNTBASE    21
  245.  
  246. #define YYTRANSLATE(x) ((unsigned)(x) <= 260 ? yytranslate[x] : 32)
  247.  
  248. static const char yytranslate[] = {     0,
  249.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  250.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  251.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  252.      2,     2,     2,     2,     2,     2,    12,     9,     2,    17,
  253.     18,    16,    14,     2,    15,    13,     2,     2,     2,     2,
  254.      2,     2,     2,     2,     2,     2,     2,     7,     2,    19,
  255.      2,    20,     6,    11,     2,     2,     2,     2,     2,     2,
  256.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  257.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  258.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  259.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  260.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  261.      2,     2,     2,     8,     2,    10,     2,     2,     2,     2,
  262.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  263.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  264.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  265.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  266.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  267.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  268.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  269.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  270.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  271.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  272.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  273.      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  274.      2,     2,     2,     2,     2,     1,     2,     3,     4,     5
  275. };
  276.  
  277. #if YYDEBUG != 0
  278. static const short yyprhs[] = {     0,
  279.      0,     2,     4,    10,    11,    13,    15,    19,    23,    25,
  280.     28,    30,    34,    36,    38,    40,    43,    46,    49,    55,
  281.     59,    63,    66,    70,    74,    75,    77,    79,    82,    84,
  282.     87,    88,    90
  283. };
  284.  
  285. #endif
  286.  
  287. static const short yyrhs[] = {    23,
  288.      0,    24,     0,    24,     6,    23,     7,    22,     0,     0,
  289.     22,     0,    25,     0,    24,     8,    25,     0,    24,     9,
  290.     25,     0,    26,     0,    25,    26,     0,    27,     0,    26,
  291.     10,    27,     0,    11,     0,     4,     0,     3,     0,     3,
  292.     29,     0,    12,     3,     0,    12,    30,     0,    27,    13,
  293.     31,     3,    28,     0,    27,    14,    29,     0,    27,    15,
  294.     29,     0,    27,    16,     0,    17,    23,    18,     0,    19,
  295.     23,    20,     0,     0,    29,     0,     5,     0,    29,     5,
  296.      0,     5,     0,    30,     5,     0,     0,    14,     0,    15,
  297.      0
  298. };
  299.  
  300. #if YYDEBUG != 0
  301. static const short yyrline[] = { 0,
  302.    248,   253,   256,   260,   263,   267,   270,   272,   276,   279,
  303.    283,   286,   290,   293,   298,   300,   302,   318,   322,   353,
  304.    355,   357,   359,   361,   365,   368,   372,   375,   379,   382,
  305.    387,   390,   392
  306. };
  307.  
  308. static const char * const yytname[] = {   "$","error","$illegal.","TOKEN_LETTER",
  309. "TOKEN_LITERAL","TOKEN_DIGIT","'?'","':'","'|'","'&'","'~'","'@'","'%'","'.'",
  310. "'+'","'-'","'*'","'('","')'","'<'","'>'","expr","conditional","optional_conditional",
  311. "alternative","list","substitute","string","optional_number","number","digits",
  312. "flag",""
  313. };
  314. #endif
  315.  
  316. static const short yyr1[] = {     0,
  317.     21,    22,    22,    23,    23,    24,    24,    24,    25,    25,
  318.     26,    26,    27,    27,    27,    27,    27,    27,    27,    27,
  319.     27,    27,    27,    27,    28,    28,    29,    29,    30,    30,
  320.     31,    31,    31
  321. };
  322.  
  323. static const short yyr2[] = {     0,
  324.      1,     1,     5,     0,     1,     1,     3,     3,     1,     2,
  325.      1,     3,     1,     1,     1,     2,     2,     2,     5,     3,
  326.      3,     2,     3,     3,     0,     1,     1,     2,     1,     2,
  327.      0,     1,     1
  328. };
  329.  
  330. static const short yydefact[] = {     4,
  331.     15,    14,    13,     0,     4,     4,     5,     1,     2,     6,
  332.      9,    11,    27,    16,    17,    29,    18,     0,     0,     4,
  333.      0,     0,    10,     0,    31,     0,     0,    22,    28,    30,
  334.     23,    24,     0,     7,     8,    12,    32,    33,     0,    20,
  335.     21,     0,    25,     3,    19,    26,     0,     0,     0
  336. };
  337.  
  338. static const short yydefgoto[] = {    47,
  339.      7,     8,     9,    10,    11,    12,    45,    14,    17,    39
  340. };
  341.  
  342. static const short yypact[] = {     0,
  343.      4,-32768,-32768,     5,     0,     0,-32768,-32768,     7,     0,
  344.     -5,    13,-32768,    15,-32768,-32768,    27,    -4,    14,     0,
  345.      0,     0,    -5,     0,     8,     4,     4,-32768,-32768,-32768,
  346. -32768,-32768,    26,     0,     0,    13,-32768,-32768,    32,    15,
  347.     15,     0,     4,-32768,-32768,    15,    36,    37,-32768
  348. };
  349.  
  350. static const short yypgoto[] = {-32768,
  351.     -3,     1,-32768,     9,   -10,    16,-32768,   -25,-32768,-32768
  352. };
  353.  
  354.  
  355. #define    YYLAST        40
  356.  
  357.  
  358. static const short yytable[] = {    23,
  359.     40,    41,     1,     2,    24,    18,    19,    15,    13,    16,
  360.      3,     4,    20,    31,    21,    22,     5,    46,     6,    29,
  361.     33,    37,    38,    23,    23,    25,    26,    27,    28,    34,
  362.     35,    30,    42,    32,    43,    48,    49,     0,    44,    36
  363. };
  364.  
  365. static const short yycheck[] = {    10,
  366.     26,    27,     3,     4,    10,     5,     6,     3,     5,     5,
  367.     11,    12,     6,    18,     8,     9,    17,    43,    19,     5,
  368.     20,    14,    15,    34,    35,    13,    14,    15,    16,    21,
  369.     22,     5,     7,    20,     3,     0,     0,    -1,    42,    24
  370. };
  371. /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
  372. #line 3 "/usr/local/lib/bison.simple"
  373.  
  374. /* Skeleton output parser for bison,
  375.    Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman
  376.  
  377.    This program is free software; you can redistribute it and/or modify
  378.    it under the terms of the GNU General Public License as published by
  379.    the Free Software Foundation; either version 1, or (at your option)
  380.    any later version.
  381.  
  382.    This program is distributed in the hope that it will be useful,
  383.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  384.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  385.    GNU General Public License for more details.
  386.  
  387.    You should have received a copy of the GNU General Public License
  388.    along with this program; if not, write to the Free Software
  389.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  390.  
  391.  
  392. #ifndef alloca
  393. #ifdef __GNUC__
  394. #define alloca __builtin_alloca
  395. #else /* not GNU C.  */
  396. #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc)
  397. #include <alloca.h>
  398. #else /* not sparc */
  399. #if defined (MSDOS) && !defined (__TURBOC__)
  400. #include <malloc.h>
  401. #else /* not MSDOS, or __TURBOC__ */
  402. #if defined(_AIX)
  403. #include <malloc.h>
  404.  #pragma alloca
  405. #endif /* not _AIX */
  406. #endif /* not MSDOS, or __TURBOC__ */
  407. #endif /* not sparc.  */
  408. #endif /* not GNU C.  */
  409. #endif /* alloca not defined.  */
  410.  
  411. /* This is the parser code that is written into each bison parser
  412.   when the %semantic_parser declaration is not specified in the grammar.
  413.   It was written by Richard Stallman by simplifying the hairy parser
  414.   used when %semantic_parser is specified.  */
  415.  
  416. /* Note: there must be only one dollar sign in this file.
  417.    It is replaced by the list of actions, each action
  418.    as one case of the switch.  */
  419.  
  420. #define yyerrok        (yyerrstatus = 0)
  421. #define yyclearin    (yychar = YYEMPTY)
  422. #define YYEMPTY        -2
  423. #define YYEOF        0
  424. #define YYACCEPT    return(0)
  425. #define YYABORT     return(1)
  426. #define YYERROR        goto yyerrlab1
  427. /* Like YYERROR except do call yyerror.
  428.    This remains here temporarily to ease the
  429.    transition to the new meaning of YYERROR, for GCC.
  430.    Once GCC version 2 has supplanted version 1, this can go.  */
  431. #define YYFAIL        goto yyerrlab
  432. #define YYRECOVERING()  (!!yyerrstatus)
  433. #define YYBACKUP(token, value) \
  434. do                                \
  435.   if (yychar == YYEMPTY && yylen == 1)                \
  436.     { yychar = (token), yylval = (value);            \
  437.       yychar1 = YYTRANSLATE (yychar);                \
  438.       YYPOPSTACK;                        \
  439.       goto yybackup;                        \
  440.     }                                \
  441.   else                                \
  442.     { yyerror ("syntax error: cannot back up"); YYERROR; }    \
  443. while (0)
  444.  
  445. #define YYTERROR    1
  446. #define YYERRCODE    256
  447.  
  448. #ifndef YYPURE
  449. #define YYLEX        yylex()
  450. #endif
  451.  
  452. #ifdef YYPURE
  453. #ifdef YYLSP_NEEDED
  454. #define YYLEX        yylex(&yylval, &yylloc)
  455. #else
  456. #define YYLEX        yylex(&yylval)
  457. #endif
  458. #endif
  459.  
  460. /* If nonreentrant, generate the variables here */
  461.  
  462. #ifndef YYPURE
  463.  
  464. int    yychar;            /*  the lookahead symbol        */
  465. YYSTYPE    yylval;            /*  the semantic value of the        */
  466.                 /*  lookahead symbol            */
  467.  
  468. #ifdef YYLSP_NEEDED
  469. YYLTYPE yylloc;            /*  location data for the lookahead    */
  470.                 /*  symbol                */
  471. #endif
  472.  
  473. int yynerrs;            /*  number of parse errors so far       */
  474. #endif  /* not YYPURE */
  475.  
  476. #if YYDEBUG != 0
  477. int yydebug;            /*  nonzero means print parse trace    */
  478. /* Since this is uninitialized, it does not stop multiple parsers
  479.    from coexisting.  */
  480. #endif
  481.  
  482. /*  YYINITDEPTH indicates the initial size of the parser's stacks    */
  483.  
  484. #ifndef    YYINITDEPTH
  485. #define YYINITDEPTH 200
  486. #endif
  487.  
  488. /*  YYMAXDEPTH is the maximum size the stacks can grow to
  489.     (effective only if the built-in stack extension method is used).  */
  490.  
  491. #if YYMAXDEPTH == 0
  492. #undef YYMAXDEPTH
  493. #endif
  494.  
  495. #ifndef YYMAXDEPTH
  496. #define YYMAXDEPTH 10000
  497. #endif
  498.  
  499. #if __GNUC__ > 1        /* GNU C and GNU C++ define this.  */
  500. #define __yy_bcopy(FROM,TO,COUNT)    __builtin_memcpy(TO,FROM,COUNT)
  501. #else                /* not GNU C or C++ */
  502. #ifndef __cplusplus
  503.  
  504. /* This is the most reliable way to avoid incompatibilities
  505.    in available built-in functions on various systems.  */
  506. static void
  507. __yy_bcopy (from, to, count)
  508.      char *from;
  509.      char *to;
  510.      int count;
  511. {
  512.   register char *f = from;
  513.   register char *t = to;
  514.   register int i = count;
  515.  
  516.   while (i-- > 0)
  517.     *t++ = *f++;
  518. }
  519.  
  520. #else /* __cplusplus */
  521.  
  522. /* This is the most reliable way to avoid incompatibilities
  523.    in available built-in functions on various systems.  */
  524. static void
  525. __yy_bcopy (char *from, char *to, int count)
  526. {
  527.   register char *f = from;
  528.   register char *t = to;
  529.   register int i = count;
  530.  
  531.   while (i-- > 0)
  532.     *t++ = *f++;
  533. }
  534.  
  535. #endif
  536. #endif
  537.  
  538. #line 169 "/usr/local/lib/bison.simple"
  539. int
  540. yyparse()
  541. {
  542.   register int yystate;
  543.   register int yyn;
  544.   register short *yyssp;
  545.   register YYSTYPE *yyvsp;
  546.   int yyerrstatus;    /*  number of tokens to shift before error messages enabled */
  547.   int yychar1;        /*  lookahead token as an internal (translated) token number */
  548.  
  549.   short    yyssa[YYINITDEPTH];    /*  the state stack            */
  550.   YYSTYPE yyvsa[YYINITDEPTH];    /*  the semantic value stack        */
  551.  
  552.   short *yyss = yyssa;        /*  refer to the stacks thru separate pointers */
  553.   YYSTYPE *yyvs = yyvsa;    /*  to allow yyoverflow to reallocate them elsewhere */
  554.  
  555. #ifdef YYLSP_NEEDED
  556.   YYLTYPE yylsa[YYINITDEPTH];    /*  the location stack            */
  557.   YYLTYPE *yyls = yylsa;
  558.   YYLTYPE *yylsp;
  559.  
  560. #define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
  561. #else
  562. #define YYPOPSTACK   (yyvsp--, yyssp--)
  563. #endif
  564.  
  565.   int yystacksize = YYINITDEPTH;
  566.  
  567. #ifdef YYPURE
  568.   int yychar;
  569.   YYSTYPE yylval;
  570.   int yynerrs;
  571. #ifdef YYLSP_NEEDED
  572.   YYLTYPE yylloc;
  573. #endif
  574. #endif
  575.  
  576.   YYSTYPE yyval;        /*  the variable used to return        */
  577.                 /*  semantic values from the action    */
  578.                 /*  routines                */
  579.  
  580.   int yylen;
  581.  
  582. #if YYDEBUG != 0
  583.   if (yydebug)
  584.     fprintf(stderr, "Starting parse\n");
  585. #endif
  586.  
  587.   yystate = 0;
  588.   yyerrstatus = 0;
  589.   yynerrs = 0;
  590.   yychar = YYEMPTY;        /* Cause a token to be read.  */
  591.  
  592.   /* Initialize stack pointers.
  593.      Waste one element of value and location stack
  594.      so that they stay on the same level as the state stack.
  595.      The wasted elements are never initialized.  */
  596.  
  597.   yyssp = yyss - 1;
  598.   yyvsp = yyvs;
  599. #ifdef YYLSP_NEEDED
  600.   yylsp = yyls;
  601. #endif
  602.  
  603. /* Push a new state, which is found in  yystate  .  */
  604. /* In all cases, when you get here, the value and location stacks
  605.    have just been pushed. so pushing a state here evens the stacks.  */
  606. yynewstate:
  607.  
  608.   *++yyssp = yystate;
  609.  
  610.   if (yyssp >= yyss + yystacksize - 1)
  611.     {
  612.       /* Give user a chance to reallocate the stack */
  613.       /* Use copies of these so that the &'s don't force the real ones into memory. */
  614.       YYSTYPE *yyvs1 = yyvs;
  615.       short *yyss1 = yyss;
  616. #ifdef YYLSP_NEEDED
  617.       YYLTYPE *yyls1 = yyls;
  618. #endif
  619.  
  620.       /* Get the current used size of the three stacks, in elements.  */
  621.       int size = yyssp - yyss + 1;
  622.  
  623. #ifdef yyoverflow
  624.       /* Each stack pointer address is followed by the size of
  625.      the data in use in that stack, in bytes.  */
  626.       yyoverflow("parser stack overflow",
  627.          &yyss1, size * sizeof (*yyssp),
  628.          &yyvs1, size * sizeof (*yyvsp),
  629. #ifdef YYLSP_NEEDED
  630.          &yyls1, size * sizeof (*yylsp),
  631. #endif
  632.          &yystacksize);
  633.  
  634.       yyss = yyss1; yyvs = yyvs1;
  635. #ifdef YYLSP_NEEDED
  636.       yyls = yyls1;
  637. #endif
  638. #else /* no yyoverflow */
  639.       /* Extend the stack our own way.  */
  640.       if (yystacksize >= YYMAXDEPTH)
  641.     {
  642.       yyerror("parser stack overflow");
  643.       return 2;
  644.     }
  645.       yystacksize *= 2;
  646.       if (yystacksize > YYMAXDEPTH)
  647.     yystacksize = YYMAXDEPTH;
  648.       yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
  649.       __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
  650.       yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
  651.       __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
  652. #ifdef YYLSP_NEEDED
  653.       yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
  654.       __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
  655. #endif
  656. #endif /* no yyoverflow */
  657.  
  658.       yyssp = yyss + size - 1;
  659.       yyvsp = yyvs + size - 1;
  660. #ifdef YYLSP_NEEDED
  661.       yylsp = yyls + size - 1;
  662. #endif
  663.  
  664. #if YYDEBUG != 0
  665.       if (yydebug)
  666.     fprintf(stderr, "Stack size increased to %d\n", yystacksize);
  667. #endif
  668.  
  669.       if (yyssp >= yyss + yystacksize - 1)
  670.     YYABORT;
  671.     }
  672.  
  673. #if YYDEBUG != 0
  674.   if (yydebug)
  675.     fprintf(stderr, "Entering state %d\n", yystate);
  676. #endif
  677.  
  678.   goto yybackup;
  679.  yybackup:
  680.  
  681. /* Do appropriate processing given the current state.  */
  682. /* Read a lookahead token if we need one and don't already have one.  */
  683. /* yyresume: */
  684.  
  685.   /* First try to decide what to do without reference to lookahead token.  */
  686.  
  687.   yyn = yypact[yystate];
  688.   if (yyn == YYFLAG)
  689.     goto yydefault;
  690.  
  691.   /* Not known => get a lookahead token if don't already have one.  */
  692.  
  693.   /* yychar is either YYEMPTY or YYEOF
  694.      or a valid token in external form.  */
  695.  
  696.   if (yychar == YYEMPTY)
  697.     {
  698. #if YYDEBUG != 0
  699.       if (yydebug)
  700.     fprintf(stderr, "Reading a token: ");
  701. #endif
  702.       yychar = YYLEX;
  703.     }
  704.  
  705.   /* Convert token to internal form (in yychar1) for indexing tables with */
  706.  
  707.   if (yychar <= 0)        /* This means end of input. */
  708.     {
  709.       yychar1 = 0;
  710.       yychar = YYEOF;        /* Don't call YYLEX any more */
  711.  
  712. #if YYDEBUG != 0
  713.       if (yydebug)
  714.     fprintf(stderr, "Now at end of input.\n");
  715. #endif
  716.     }
  717.   else
  718.     {
  719.       yychar1 = YYTRANSLATE(yychar);
  720.  
  721. #if YYDEBUG != 0
  722.       if (yydebug)
  723.     {
  724.       fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
  725.       /* Give the individual parser a way to print the precise meaning
  726.          of a token, for further debugging info.  */
  727. #ifdef YYPRINT
  728.       YYPRINT (stderr, yychar, yylval);
  729. #endif
  730.       fprintf (stderr, ")\n");
  731.     }
  732. #endif
  733.     }
  734.  
  735.   yyn += yychar1;
  736.   if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
  737.     goto yydefault;
  738.  
  739.   yyn = yytable[yyn];
  740.  
  741.   /* yyn is what to do for this token type in this state.
  742.      Negative => reduce, -yyn is rule number.
  743.      Positive => shift, yyn is new state.
  744.        New state is final state => don't bother to shift,
  745.        just return success.
  746.      0, or most negative number => error.  */
  747.  
  748.   if (yyn < 0)
  749.     {
  750.       if (yyn == YYFLAG)
  751.     goto yyerrlab;
  752.       yyn = -yyn;
  753.       goto yyreduce;
  754.     }
  755.   else if (yyn == 0)
  756.     goto yyerrlab;
  757.  
  758.   if (yyn == YYFINAL)
  759.     YYACCEPT;
  760.  
  761.   /* Shift the lookahead token.  */
  762.  
  763. #if YYDEBUG != 0
  764.   if (yydebug)
  765.     fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
  766. #endif
  767.  
  768.   /* Discard the token being shifted unless it is eof.  */
  769.   if (yychar != YYEOF)
  770.     yychar = YYEMPTY;
  771.  
  772.   *++yyvsp = yylval;
  773. #ifdef YYLSP_NEEDED
  774.   *++yylsp = yylloc;
  775. #endif
  776.  
  777.   /* count tokens shifted since error; after three, turn off error status.  */
  778.   if (yyerrstatus) yyerrstatus--;
  779.  
  780.   yystate = yyn;
  781.   goto yynewstate;
  782.  
  783. /* Do the default action for the current state.  */
  784. yydefault:
  785.  
  786.   yyn = yydefact[yystate];
  787.   if (yyn == 0)
  788.     goto yyerrlab;
  789.  
  790. /* Do a reduction.  yyn is the number of a rule to reduce with.  */
  791. yyreduce:
  792.   yylen = yyr2[yyn];
  793.   yyval = yyvsp[1-yylen]; /* implement default value of the action */
  794.  
  795. #if YYDEBUG != 0
  796.   if (yydebug)
  797.     {
  798.       int i;
  799.  
  800.       fprintf (stderr, "Reducing via rule %d (line %d), ",
  801.            yyn, yyrline[yyn]);
  802.  
  803.       /* Print the symbols being reduced, and their result.  */
  804.       for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
  805.     fprintf (stderr, "%s ", yytname[yyrhs[i]]);
  806.       fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
  807.     }
  808. #endif
  809.  
  810.  
  811.   switch (yyn) {
  812.  
  813. case 1:
  814. #line 250 "label.y"
  815. { parse_result = (yyvsp[0].expr ? new analyzed_expr(yyvsp[0].expr) : 0); ;
  816.     break;}
  817. case 2:
  818. #line 255 "label.y"
  819. { yyval.expr = yyvsp[0].expr; ;
  820.     break;}
  821. case 3:
  822. #line 257 "label.y"
  823. { yyval.expr = new conditional_expr(yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); ;
  824.     break;}
  825. case 4:
  826. #line 262 "label.y"
  827. { yyval.expr = 0; ;
  828.     break;}
  829. case 5:
  830. #line 264 "label.y"
  831. { yyval.expr = yyvsp[0].expr; ;
  832.     break;}
  833. case 6:
  834. #line 269 "label.y"
  835. { yyval.expr = yyvsp[0].expr; ;
  836.     break;}
  837. case 7:
  838. #line 271 "label.y"
  839. { yyval.expr = new alternative_expr(yyvsp[-2].expr, yyvsp[0].expr); ;
  840.     break;}
  841. case 8:
  842. #line 273 "label.y"
  843. { yyval.expr = new conditional_expr(yyvsp[-2].expr, yyvsp[0].expr, 0); ;
  844.     break;}
  845. case 9:
  846. #line 278 "label.y"
  847. { yyval.expr = yyvsp[0].expr; ;
  848.     break;}
  849. case 10:
  850. #line 280 "label.y"
  851. { yyval.expr = new list_expr(yyvsp[-1].expr, yyvsp[0].expr); ;
  852.     break;}
  853. case 11:
  854. #line 285 "label.y"
  855. { yyval.expr = yyvsp[0].expr; ;
  856.     break;}
  857. case 12:
  858. #line 287 "label.y"
  859. { yyval.expr = new substitute_expr(yyvsp[-2].expr, yyvsp[0].expr); ;
  860.     break;}
  861. case 13:
  862. #line 292 "label.y"
  863. { yyval.expr = new at_expr; ;
  864.     break;}
  865. case 14:
  866. #line 294 "label.y"
  867. {
  868.           yyval.expr = new literal_expr(literals.contents() + yyvsp[0].str.start,
  869.                     yyvsp[0].str.len);
  870.         ;
  871.     break;}
  872. case 15:
  873. #line 299 "label.y"
  874. { yyval.expr = new field_expr(yyvsp[0].num, 0); ;
  875.     break;}
  876. case 16:
  877. #line 301 "label.y"
  878. { yyval.expr = new field_expr(yyvsp[-1].num, yyvsp[0].num - 1); ;
  879.     break;}
  880. case 17:
  881. #line 303 "label.y"
  882. {
  883.           switch (yyvsp[0].num) {
  884.           case 'I':
  885.           case 'i':
  886.           case 'A':
  887.           case 'a':
  888.             yyval.expr = new format_expr(yyvsp[0].num);
  889.             break;
  890.           default:
  891.             command_error("unrecognized format `%1'", char(yyvsp[0].num));
  892.             yyval.expr = new format_expr('a');
  893.             break;
  894.           }
  895.         ;
  896.     break;}
  897. case 18:
  898. #line 319 "label.y"
  899. {
  900.           yyval.expr = new format_expr('0', yyvsp[0].dig.ndigits, yyvsp[0].dig.val);
  901.         ;
  902.     break;}
  903. case 19:
  904. #line 323 "label.y"
  905. {
  906.           switch (yyvsp[-1].num) {
  907.           case 'l':
  908.             yyval.expr = new map_expr(yyvsp[-4].expr, lowercase);
  909.             break;
  910.           case 'u':
  911.             yyval.expr = new map_expr(yyvsp[-4].expr, uppercase);
  912.             break;
  913.           case 'c':
  914.             yyval.expr = new map_expr(yyvsp[-4].expr, capitalize);
  915.             break;
  916.           case 'r':
  917.             yyval.expr = new map_expr(yyvsp[-4].expr, reverse_name);
  918.             break;
  919.           case 'a':
  920.             yyval.expr = new map_expr(yyvsp[-4].expr, abbreviate_name);
  921.             break;
  922.           case 'y':
  923.             yyval.expr = new extractor_expr(yyvsp[-4].expr, find_year, yyvsp[-2].num);
  924.             break;
  925.           case 'n':
  926.             yyval.expr = new extractor_expr(yyvsp[-4].expr, find_last_name, yyvsp[-2].num);
  927.             break;
  928.           default:
  929.             yyval.expr = yyvsp[-4].expr;
  930.             command_error("unknown function `%1'", char(yyvsp[-1].num));
  931.             break;
  932.           }
  933.         ;
  934.     break;}
  935. case 20:
  936. #line 354 "label.y"
  937. { yyval.expr = new truncate_expr(yyvsp[-2].expr, yyvsp[0].num); ;
  938.     break;}
  939. case 21:
  940. #line 356 "label.y"
  941. { yyval.expr = new truncate_expr(yyvsp[-2].expr, -yyvsp[0].num); ;
  942.     break;}
  943. case 22:
  944. #line 358 "label.y"
  945. { yyval.expr = new star_expr(yyvsp[-1].expr); ;
  946.     break;}
  947. case 23:
  948. #line 360 "label.y"
  949. { yyval.expr = yyvsp[-1].expr; ;
  950.     break;}
  951. case 24:
  952. #line 362 "label.y"
  953. { yyval.expr = new separator_expr(yyvsp[-1].expr); ;
  954.     break;}
  955. case 25:
  956. #line 367 "label.y"
  957. { yyval.num = -1; ;
  958.     break;}
  959. case 26:
  960. #line 369 "label.y"
  961. { yyval.num = yyvsp[0].num; ;
  962.     break;}
  963. case 27:
  964. #line 374 "label.y"
  965. { yyval.num = yyvsp[0].num; ;
  966.     break;}
  967. case 28:
  968. #line 376 "label.y"
  969. { yyval.num = yyvsp[-1].num*10 + yyvsp[0].num; ;
  970.     break;}
  971. case 29:
  972. #line 381 "label.y"
  973. { yyval.dig.ndigits = 1; yyval.dig.val = yyvsp[0].num; ;
  974.     break;}
  975. case 30:
  976. #line 383 "label.y"
  977. { yyval.dig.ndigits = yyvsp[-1].dig.ndigits + 1; yyval.dig.val = yyvsp[-1].dig.val*10 + yyvsp[0].num; ;
  978.     break;}
  979. case 31:
  980. #line 389 "label.y"
  981. { yyval.num = 0; ;
  982.     break;}
  983. case 32:
  984. #line 391 "label.y"
  985. { yyval.num = 1; ;
  986.     break;}
  987. case 33:
  988. #line 393 "label.y"
  989. { yyval.num = -1; ;
  990.     break;}
  991. }
  992.    /* the action file gets copied in in place of this dollarsign */
  993. #line 442 "/usr/local/lib/bison.simple"
  994.  
  995.   yyvsp -= yylen;
  996.   yyssp -= yylen;
  997. #ifdef YYLSP_NEEDED
  998.   yylsp -= yylen;
  999. #endif
  1000.  
  1001. #if YYDEBUG != 0
  1002.   if (yydebug)
  1003.     {
  1004.       short *ssp1 = yyss - 1;
  1005.       fprintf (stderr, "state stack now");
  1006.       while (ssp1 != yyssp)
  1007.     fprintf (stderr, " %d", *++ssp1);
  1008.       fprintf (stderr, "\n");
  1009.     }
  1010. #endif
  1011.  
  1012.   *++yyvsp = yyval;
  1013.  
  1014. #ifdef YYLSP_NEEDED
  1015.   yylsp++;
  1016.   if (yylen == 0)
  1017.     {
  1018.       yylsp->first_line = yylloc.first_line;
  1019.       yylsp->first_column = yylloc.first_column;
  1020.       yylsp->last_line = (yylsp-1)->last_line;
  1021.       yylsp->last_column = (yylsp-1)->last_column;
  1022.       yylsp->text = 0;
  1023.     }
  1024.   else
  1025.     {
  1026.       yylsp->last_line = (yylsp+yylen-1)->last_line;
  1027.       yylsp->last_column = (yylsp+yylen-1)->last_column;
  1028.     }
  1029. #endif
  1030.  
  1031.   /* Now "shift" the result of the reduction.
  1032.      Determine what state that goes to,
  1033.      based on the state we popped back to
  1034.      and the rule number reduced by.  */
  1035.  
  1036.   yyn = yyr1[yyn];
  1037.  
  1038.   yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
  1039.   if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
  1040.     yystate = yytable[yystate];
  1041.   else
  1042.     yystate = yydefgoto[yyn - YYNTBASE];
  1043.  
  1044.   goto yynewstate;
  1045.  
  1046. yyerrlab:   /* here on detecting error */
  1047.  
  1048.   if (! yyerrstatus)
  1049.     /* If not already recovering from an error, report this error.  */
  1050.     {
  1051.       ++yynerrs;
  1052.  
  1053. #ifdef YYERROR_VERBOSE
  1054.       yyn = yypact[yystate];
  1055.  
  1056.       if (yyn > YYFLAG && yyn < YYLAST)
  1057.     {
  1058.       int size = 0;
  1059.       char *msg;
  1060.       int x, count;
  1061.  
  1062.       count = 0;
  1063.       for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
  1064.         if (yycheck[x + yyn] == x)
  1065.           size += strlen(yytname[x]) + 15, count++;
  1066.       msg = (char *) malloc(size + 15);
  1067.       if (msg != 0)
  1068.         {
  1069.           strcpy(msg, "parse error");
  1070.  
  1071.           if (count < 5)
  1072.         {
  1073.           count = 0;
  1074.           for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
  1075.             if (yycheck[x + yyn] == x)
  1076.               {
  1077.             strcat(msg, count == 0 ? ", expecting `" : " or `");
  1078.             strcat(msg, yytname[x]);
  1079.             strcat(msg, "'");
  1080.             count++;
  1081.               }
  1082.         }
  1083.           yyerror(msg);
  1084.           free(msg);
  1085.         }
  1086.       else
  1087.         yyerror ("parse error; also virtual memory exceeded");
  1088.     }
  1089.       else
  1090. #endif /* YYERROR_VERBOSE */
  1091.     yyerror("parse error");
  1092.     }
  1093.  
  1094.   goto yyerrlab1;
  1095. yyerrlab1:   /* here on error raised explicitly by an action */
  1096.  
  1097.   if (yyerrstatus == 3)
  1098.     {
  1099.       /* if just tried and failed to reuse lookahead token after an error, discard it.  */
  1100.  
  1101.       /* return failure if at end of input */
  1102.       if (yychar == YYEOF)
  1103.     YYABORT;
  1104.  
  1105. #if YYDEBUG != 0
  1106.       if (yydebug)
  1107.     fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
  1108. #endif
  1109.  
  1110.       yychar = YYEMPTY;
  1111.     }
  1112.  
  1113.   /* Else will try to reuse lookahead token
  1114.      after shifting the error token.  */
  1115.  
  1116.   yyerrstatus = 3;        /* Each real token shifted decrements this */
  1117.  
  1118.   goto yyerrhandle;
  1119.  
  1120. yyerrdefault:  /* current state does not do anything special for the error token. */
  1121.  
  1122. #if 0
  1123.   /* This is wrong; only states that explicitly want error tokens
  1124.      should shift them.  */
  1125.   yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
  1126.   if (yyn) goto yydefault;
  1127. #endif
  1128.  
  1129. yyerrpop:   /* pop the current state because it cannot handle the error token */
  1130.  
  1131.   if (yyssp == yyss) YYABORT;
  1132.   yyvsp--;
  1133.   yystate = *--yyssp;
  1134. #ifdef YYLSP_NEEDED
  1135.   yylsp--;
  1136. #endif
  1137.  
  1138. #if YYDEBUG != 0
  1139.   if (yydebug)
  1140.     {
  1141.       short *ssp1 = yyss - 1;
  1142.       fprintf (stderr, "Error: state stack now");
  1143.       while (ssp1 != yyssp)
  1144.     fprintf (stderr, " %d", *++ssp1);
  1145.       fprintf (stderr, "\n");
  1146.     }
  1147. #endif
  1148.  
  1149. yyerrhandle:
  1150.  
  1151.   yyn = yypact[yystate];
  1152.   if (yyn == YYFLAG)
  1153.     goto yyerrdefault;
  1154.  
  1155.   yyn += YYTERROR;
  1156.   if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
  1157.     goto yyerrdefault;
  1158.  
  1159.   yyn = yytable[yyn];
  1160.   if (yyn < 0)
  1161.     {
  1162.       if (yyn == YYFLAG)
  1163.     goto yyerrpop;
  1164.       yyn = -yyn;
  1165.       goto yyreduce;
  1166.     }
  1167.   else if (yyn == 0)
  1168.     goto yyerrpop;
  1169.  
  1170.   if (yyn == YYFINAL)
  1171.     YYACCEPT;
  1172.  
  1173. #if YYDEBUG != 0
  1174.   if (yydebug)
  1175.     fprintf(stderr, "Shifting error token, ");
  1176. #endif
  1177.  
  1178.   *++yyvsp = yylval;
  1179. #ifdef YYLSP_NEEDED
  1180.   *++yylsp = yylloc;
  1181. #endif
  1182.  
  1183.   yystate = yyn;
  1184.   goto yynewstate;
  1185. }
  1186. #line 396 "label.y"
  1187.  
  1188.  
  1189. /* bison defines const to be empty unless __STDC__ is defined, which it
  1190. isn't under cfront */
  1191.  
  1192. #ifdef const
  1193. #undef const
  1194. #endif
  1195.  
  1196. const char *spec_ptr;
  1197. const char *spec_end;
  1198. const char *spec_cur;
  1199.  
  1200. int yylex()
  1201. {
  1202.   while (spec_ptr < spec_end && csspace(*spec_ptr))
  1203.     spec_ptr++;
  1204.   spec_cur = spec_ptr;
  1205.   if (spec_ptr >= spec_end)
  1206.     return 0;
  1207.   unsigned char c = *spec_ptr++;
  1208.   if (csalpha(c)) {
  1209.     yylval.num = c;
  1210.     return TOKEN_LETTER;
  1211.   }
  1212.   if (csdigit(c)) {
  1213.     yylval.num = c - '0';
  1214.     return TOKEN_DIGIT;
  1215.   }
  1216.   if (c == '\'') {
  1217.     yylval.str.start = literals.length();
  1218.     for (; spec_ptr < spec_end; spec_ptr++) {
  1219.       if (*spec_ptr == '\'') {
  1220.     if (++spec_ptr < spec_end && *spec_ptr == '\'')
  1221.       literals += '\'';
  1222.     else {
  1223.       yylval.str.len = literals.length() - yylval.str.start;
  1224.       return TOKEN_LITERAL;
  1225.     }
  1226.       }
  1227.       else
  1228.     literals += *spec_ptr;
  1229.     }
  1230.     yylval.str.len = literals.length() - yylval.str.start;
  1231.     return TOKEN_LITERAL;
  1232.   }
  1233.   return c;
  1234. }
  1235.  
  1236. int set_label_spec(const char *label_spec)
  1237. {
  1238.   spec_cur = spec_ptr = label_spec;
  1239.   spec_end = strchr(label_spec, '\0');
  1240.   literals.clear();
  1241.   if (yyparse())
  1242.     return 0;
  1243.   delete parsed_label;
  1244.   parsed_label = parse_result;
  1245.   return 1;
  1246. }
  1247.  
  1248. int set_date_label_spec(const char *label_spec)
  1249. {
  1250.   spec_cur = spec_ptr = label_spec;
  1251.   spec_end = strchr(label_spec, '\0');
  1252.   literals.clear();
  1253.   if (yyparse())
  1254.     return 0;
  1255.   delete parsed_date_label;
  1256.   parsed_date_label = parse_result;
  1257.   return 1;
  1258. }
  1259.  
  1260. int set_short_label_spec(const char *label_spec)
  1261. {
  1262.   spec_cur = spec_ptr = label_spec;
  1263.   spec_end = strchr(label_spec, '\0');
  1264.   literals.clear();
  1265.   if (yyparse())
  1266.     return 0;
  1267.   delete parsed_short_label;
  1268.   parsed_short_label = parse_result;
  1269.   return 1;
  1270. }
  1271.  
  1272. void yyerror(const char *message)
  1273. {
  1274.   if (spec_cur < spec_end)
  1275.     command_error("label specification %1 before `%2'", message, spec_cur);
  1276.   else
  1277.     command_error("label specification %1 at end of string",
  1278.           message, spec_cur);
  1279. }
  1280.  
  1281. void at_expr::evaluate(int tentative, const reference &ref,
  1282.                string &result, substring_position &)
  1283. {
  1284.   if (tentative)
  1285.     ref.canonicalize_authors(result);
  1286.   else {
  1287.     const char *end, *start = ref.get_authors(&end);
  1288.     if (start)
  1289.       result.append(start, end - start);
  1290.   }
  1291. }
  1292.  
  1293. void format_expr::evaluate(int tentative, const reference &ref,
  1294.                string &result, substring_position &)
  1295. {
  1296.   if (tentative)
  1297.     return;
  1298.   const label_info *lp = ref.get_label_ptr();
  1299.   int num = lp == 0 ? ref.get_number() : lp->count;
  1300.   if (type != '0')
  1301.     result += format_serial(type, num + 1);
  1302.   else {
  1303.     const char *ptr = itoa(num + first_number);
  1304.     int pad = width - strlen(ptr);
  1305.     while (--pad >= 0)
  1306.       result += '0';
  1307.     result += ptr;
  1308.   }
  1309. }
  1310.  
  1311. static const char *format_serial(char c, int n)
  1312. {
  1313.   assert(n > 0);
  1314.   static char buf[128]; // more than enough.
  1315.   switch (c) {
  1316.   case 'i':
  1317.   case 'I':
  1318.     {
  1319.       char *p = buf;
  1320.       // troff uses z and w to represent 10000 and 5000 in Roman
  1321.       // numerals; I can find no historical basis for this usage
  1322.       const char *s = c == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
  1323.       if (n >= 40000)
  1324.     return itoa(n);
  1325.       while (n >= 10000) {
  1326.     *p++ = s[0];
  1327.     n -= 10000;
  1328.       }
  1329.       for (int i = 1000; i > 0; i /= 10, s += 2) {
  1330.     int m = n/i;
  1331.     n -= m*i;
  1332.     switch (m) {
  1333.     case 3:
  1334.       *p++ = s[2];
  1335.       /* falls through */
  1336.     case 2:
  1337.       *p++ = s[2];
  1338.       /* falls through */
  1339.     case 1:
  1340.       *p++ = s[2];
  1341.       break;
  1342.     case 4:
  1343.       *p++ = s[2];
  1344.       *p++ = s[1];
  1345.       break;
  1346.     case 8:
  1347.       *p++ = s[1];
  1348.       *p++ = s[2];
  1349.       *p++ = s[2];
  1350.       *p++ = s[2];
  1351.       break;
  1352.     case 7:
  1353.       *p++ = s[1];
  1354.       *p++ = s[2];
  1355.       *p++ = s[2];
  1356.       break;
  1357.     case 6:
  1358.       *p++ = s[1];
  1359.       *p++ = s[2];
  1360.       break;
  1361.     case 5:
  1362.       *p++ = s[1];
  1363.       break;
  1364.     case 9:
  1365.       *p++ = s[2];
  1366.       *p++ = s[0];
  1367.     }
  1368.       }
  1369.       *p = 0;
  1370.       break;
  1371.     }
  1372.   case 'a':
  1373.   case 'A':
  1374.     {
  1375.       char *p = buf;
  1376.       // this is derived from troff/reg.c
  1377.       while (n > 0) {
  1378.     int d = n % 26;
  1379.     if (d == 0)
  1380.       d = 26;
  1381.     n -= d;
  1382.     n /= 26;
  1383.     *p++ = c + d - 1;    // ASCII dependent
  1384.       }
  1385.       *p-- = 0;
  1386.       // Reverse it.
  1387.       char *q = buf;
  1388.       while (q < p) {
  1389.     char temp = *q;
  1390.     *q = *p;
  1391.     *p = temp;
  1392.     --p;
  1393.     ++q;
  1394.       }
  1395.       break;
  1396.     }
  1397.   default:
  1398.     assert(0);
  1399.   }
  1400.   return buf;
  1401. }
  1402.  
  1403. void field_expr::evaluate(int, const reference &ref,
  1404.               string &result, substring_position &)
  1405. {
  1406.   const char *end;
  1407.   const char *start = ref.get_field(name, &end);
  1408.   if (start) {
  1409.     start = nth_field(number, start, &end);
  1410.     if (start)
  1411.       result.append(start, end - start);
  1412.   }
  1413. }
  1414.  
  1415. void literal_expr::evaluate(int, const reference &,
  1416.                 string &result, substring_position &)
  1417. {
  1418.   result += s;
  1419. }
  1420.  
  1421. analyzed_expr::analyzed_expr(expression *e)
  1422. : unary_expr(e), flags(e ? e->analyze() : 0)
  1423. {
  1424. }
  1425.  
  1426. void analyzed_expr::evaluate(int tentative, const reference &ref,
  1427.                  string &result, substring_position &pos)
  1428. {
  1429.   if (expr)
  1430.     expr->evaluate(tentative, ref, result, pos);
  1431. }
  1432.  
  1433. void star_expr::evaluate(int tentative, const reference &ref,
  1434.              string &result, substring_position &pos)
  1435. {
  1436.   const label_info *lp = ref.get_label_ptr();
  1437.   if (!tentative
  1438.       && (lp == 0 || lp->total > 1)
  1439.       && expr)
  1440.     expr->evaluate(tentative, ref, result, pos);
  1441. }
  1442.  
  1443. void separator_expr::evaluate(int tentative, const reference &ref,
  1444.                   string &result, substring_position &pos)
  1445. {
  1446.   int start_length = result.length();
  1447.   int is_first = pos.start < 0;
  1448.   if (expr)
  1449.     expr->evaluate(tentative, ref, result, pos);
  1450.   if (is_first) {
  1451.     pos.start = start_length;
  1452.     pos.length = result.length() - start_length;
  1453.   }
  1454. }
  1455.  
  1456. void map_expr::evaluate(int tentative, const reference &ref,
  1457.             string &result, substring_position &)
  1458. {
  1459.   if (expr) {
  1460.     string temp;
  1461.     substring_position temp_pos;
  1462.     expr->evaluate(tentative, ref, temp, temp_pos);
  1463.     (*func)(temp.contents(), temp.contents() + temp.length(), result);
  1464.   }
  1465. }
  1466.  
  1467. void extractor_expr::evaluate(int tentative, const reference &ref,
  1468.                   string &result, substring_position &)
  1469. {
  1470.   if (expr) {
  1471.     string temp;
  1472.     substring_position temp_pos;
  1473.     expr->evaluate(tentative, ref, temp, temp_pos);
  1474.     const char *end, *start = (*func)(temp.contents(),
  1475.                       temp.contents() + temp.length(),
  1476.                       &end);
  1477.     switch (part) {
  1478.     case BEFORE:
  1479.       if (start)
  1480.     result.append(temp.contents(), start - temp.contents());
  1481.       else
  1482.     result += temp;
  1483.       break;
  1484.     case MATCH:
  1485.       if (start)
  1486.     result.append(start, end - start);
  1487.       break;
  1488.     case AFTER:
  1489.       if (start)
  1490.     result.append(end, temp.contents() + temp.length() - end);
  1491.       break;
  1492.     default:
  1493.       assert(0);
  1494.     }
  1495.   }
  1496. }
  1497.  
  1498. static void first_part(int len, const char *ptr, const char *end,
  1499.               string &result)
  1500. {
  1501.   for (;;) {
  1502.     const char *token_start = ptr;
  1503.     if (!get_token(&ptr, end))
  1504.       break;
  1505.     const token_info *ti = lookup_token(token_start, ptr);
  1506.     int counts = ti->sortify_non_empty(token_start, ptr);
  1507.     if (counts && --len < 0)
  1508.       break;
  1509.     if (counts || ti->is_accent())
  1510.       result.append(token_start, ptr - token_start);
  1511.   }
  1512. }
  1513.  
  1514. static void last_part(int len, const char *ptr, const char *end,
  1515.               string &result)
  1516. {
  1517.   const char *start = ptr;
  1518.   int count = 0;
  1519.   for (;;) {
  1520.     const char *token_start = ptr;
  1521.     if (!get_token(&ptr, end))
  1522.       break;
  1523.     const token_info *ti = lookup_token(token_start, ptr);
  1524.     if (ti->sortify_non_empty(token_start, ptr))
  1525.       count++;
  1526.   }
  1527.   ptr = start;
  1528.   int skip = count - len;
  1529.   if (skip > 0) {
  1530.     for (;;) {
  1531.       const char *token_start = ptr;
  1532.       if (!get_token(&ptr, end))
  1533.     assert(0);
  1534.       const token_info *ti = lookup_token(token_start, ptr);
  1535.       if (ti->sortify_non_empty(token_start, ptr) && --skip < 0) {
  1536.     ptr = token_start;
  1537.     break;
  1538.       }
  1539.     }
  1540.   }
  1541.   first_part(len, ptr, end, result);
  1542. }
  1543.  
  1544. void truncate_expr::evaluate(int tentative, const reference &ref,
  1545.                  string &result, substring_position &)
  1546. {
  1547.   if (expr) {
  1548.     string temp;
  1549.     substring_position temp_pos;
  1550.     expr->evaluate(tentative, ref, temp, temp_pos);
  1551.     const char *start = temp.contents();
  1552.     const char *end = start + temp.length();
  1553.     if (n > 0)
  1554.       first_part(n, start, end, result);
  1555.     else if (n < 0)
  1556.       last_part(-n, start, end, result);
  1557.   }
  1558. }
  1559.  
  1560. void alternative_expr::evaluate(int tentative, const reference &ref,
  1561.                 string &result, substring_position &pos)
  1562. {
  1563.   int start_length = result.length();
  1564.   if (expr1)
  1565.     expr1->evaluate(tentative, ref, result, pos);
  1566.   if (result.length() == start_length && expr2)
  1567.     expr2->evaluate(tentative, ref, result, pos);
  1568. }
  1569.  
  1570. void list_expr::evaluate(int tentative, const reference &ref,
  1571.              string &result, substring_position &pos)
  1572. {
  1573.   if (expr1)
  1574.     expr1->evaluate(tentative, ref, result, pos);
  1575.   if (expr2)
  1576.     expr2->evaluate(tentative, ref, result, pos);
  1577. }
  1578.  
  1579. void substitute_expr::evaluate(int tentative, const reference &ref,
  1580.                    string &result, substring_position &pos)
  1581. {
  1582.   int start_length = result.length();
  1583.   if (expr1)
  1584.     expr1->evaluate(tentative, ref, result, pos);
  1585.   if (result.length() > start_length && result[result.length() - 1] == '-') {
  1586.     // ought to see if pos covers the -
  1587.     result.set_length(result.length() - 1);
  1588.     if (expr2)
  1589.       expr2->evaluate(tentative, ref, result, pos);
  1590.   }
  1591. }
  1592.  
  1593. void conditional_expr::evaluate(int tentative, const reference &ref,
  1594.                 string &result, substring_position &pos)
  1595. {
  1596.   string temp;
  1597.   substring_position temp_pos;
  1598.   if (expr1)
  1599.     expr1->evaluate(tentative, ref, temp, temp_pos);
  1600.   if (temp.length() > 0) {
  1601.     if (expr2)
  1602.       expr2->evaluate(tentative, ref, result, pos);
  1603.   }
  1604.   else {
  1605.     if (expr3)
  1606.       expr3->evaluate(tentative, ref, result, pos);
  1607.   }
  1608. }
  1609.  
  1610. void reference::pre_compute_label()
  1611. {
  1612.   if (parsed_label != 0
  1613.       && (parsed_label->analyze() & expression::CONTAINS_VARIABLE)) {
  1614.     label.clear();
  1615.     substring_position temp_pos;
  1616.     parsed_label->evaluate(1, *this, label, temp_pos);
  1617.     label_ptr = lookup_label(label);
  1618.   }
  1619. }
  1620.  
  1621. void reference::compute_label()
  1622. {
  1623.   label.clear();
  1624.   if (parsed_label)
  1625.     parsed_label->evaluate(0, *this, label, separator_pos);
  1626.   if (short_label_flag && parsed_short_label)
  1627.     parsed_short_label->evaluate(0, *this, short_label, short_separator_pos);
  1628.   if (date_as_label) {
  1629.     string new_date;
  1630.     if (parsed_date_label) {
  1631.       substring_position temp_pos;
  1632.       parsed_date_label->evaluate(0, *this, new_date, temp_pos);
  1633.     }
  1634.     set_date(new_date);
  1635.   }
  1636.   if (label_ptr)
  1637.     label_ptr->count += 1;
  1638. }
  1639.  
  1640. void reference::immediate_compute_label()
  1641. {
  1642.   if (label_ptr)
  1643.     label_ptr->total = 2;    // force use of disambiguator
  1644.   compute_label();
  1645. }
  1646.  
  1647. int reference::merge_labels(reference **v, int n, label_type type,
  1648.                 string &result)
  1649. {
  1650.   if (abbreviate_label_ranges)
  1651.     return merge_labels_by_number(v, n, type, result);
  1652.   else
  1653.     return merge_labels_by_parts(v, n, type, result);
  1654. }
  1655.  
  1656. int reference::merge_labels_by_number(reference **v, int n, label_type type,
  1657.                       string &result)
  1658. {
  1659.   if (n <= 1)
  1660.     return 0;
  1661.   int num = get_number();
  1662.   // Only merge three or more labels.
  1663.   if (v[0]->get_number() != num + 1
  1664.       || v[1]->get_number() != num + 2)
  1665.     return 0;
  1666.   for (int i = 2; i < n; i++)
  1667.     if (v[i]->get_number() != num + i + 1)
  1668.       break;
  1669.   result = get_label(type);
  1670.   result += label_range_indicator;
  1671.   result += v[i - 1]->get_label(type);
  1672.   return i;
  1673. }
  1674.  
  1675. const substring_position &reference::get_separator_pos(label_type type) const
  1676. {
  1677.   if (type == SHORT_LABEL && short_label_flag)
  1678.     return short_separator_pos;
  1679.   else
  1680.     return separator_pos;
  1681. }
  1682.  
  1683. const string &reference::get_label(label_type type) const
  1684. {
  1685.   if (type == SHORT_LABEL && short_label_flag)
  1686.     return short_label; 
  1687.   else
  1688.     return label;
  1689. }
  1690.  
  1691. int reference::merge_labels_by_parts(reference **v, int n, label_type type,
  1692.                      string &result)
  1693. {
  1694.   if (n <= 0)
  1695.     return 0;
  1696.   const string &lb = get_label(type);
  1697.   const substring_position &sp = get_separator_pos(type);
  1698.   if (sp.start < 0
  1699.       || sp.start != v[0]->get_separator_pos(type).start 
  1700.       || memcmp(lb.contents(), v[0]->get_label(type).contents(),
  1701.         sp.start) != 0)
  1702.     return 0;
  1703.   result = lb;
  1704.   int i = 0;
  1705.   do {
  1706.     result += separate_label_second_parts;
  1707.     const substring_position &s = v[i]->get_separator_pos(type);
  1708.     int sep_end_pos = s.start + s.length;
  1709.     result.append(v[i]->get_label(type).contents() + sep_end_pos,
  1710.           v[i]->get_label(type).length() - sep_end_pos);
  1711.   } while (++i < n
  1712.        && sp.start == v[i]->get_separator_pos(type).start
  1713.        && memcmp(lb.contents(), v[i]->get_label(type).contents(),
  1714.              sp.start) == 0);
  1715.   return i;
  1716. }
  1717.  
  1718. string label_pool;
  1719.  
  1720. label_info::label_info(const string &s)
  1721. : count(0), total(1), length(s.length()), start(label_pool.length())
  1722. {
  1723.   label_pool += s;
  1724. }
  1725.  
  1726. static label_info **label_table = 0;
  1727. static int label_table_size = 0;
  1728. static int label_table_used = 0;
  1729.  
  1730. label_info *lookup_label(const string &label)
  1731. {
  1732.   if (label_table == 0) {
  1733.     label_table = new label_info *[17];
  1734.     label_table_size = 17;
  1735.     for (int i = 0; i < 17; i++)
  1736.       label_table[i] = 0;
  1737.   }
  1738.   unsigned h = hash_string(label.contents(), label.length()) % label_table_size;
  1739.   for (label_info **ptr = label_table + h;
  1740.        *ptr != 0;
  1741.        (ptr == label_table)
  1742.        ? (ptr = label_table + label_table_size - 1)
  1743.        : ptr--)
  1744.     if ((*ptr)->length == label.length()
  1745.     && memcmp(label_pool.contents() + (*ptr)->start, label.contents(),
  1746.           label.length()) == 0) {
  1747.       (*ptr)->total += 1;
  1748.       return *ptr;
  1749.     }
  1750.   label_info *result = *ptr = new label_info(label);
  1751.   if (++label_table_used * 2 > label_table_size) {
  1752.     // Rehash the table.
  1753.     label_info **old_table = label_table;
  1754.     int old_size = label_table_size;
  1755.     label_table_size = next_size(label_table_size);
  1756.     label_table = new label_info *[label_table_size];
  1757.     int i;
  1758.     for (i = 0; i < label_table_size; i++)
  1759.       label_table[i] = 0;
  1760.     for (i = 0; i < old_size; i++)
  1761.       if (old_table[i]) {
  1762.     unsigned h = hash_string(label_pool.contents() + old_table[i]->start,
  1763.                  old_table[i]->length);
  1764.     for (label_info **p = label_table + (h % label_table_size);
  1765.          *p != 0;
  1766.          (p == label_table)
  1767.          ? (p = label_table + label_table_size - 1)
  1768.          : --p)
  1769.         ;
  1770.     *p = old_table[i];
  1771.     }
  1772.     a_delete old_table;
  1773.   }
  1774.   return result;
  1775. }
  1776.  
  1777. void clear_labels()
  1778. {
  1779.   for (int i = 0; i < label_table_size; i++) {
  1780.     delete label_table[i];
  1781.     label_table[i] = 0;
  1782.   }
  1783.   label_table_used = 0;
  1784.   label_pool.clear();
  1785. }
  1786.  
  1787. static void consider_authors(reference **start, reference **end, int i);
  1788.  
  1789. void compute_labels(reference **v, int n)
  1790. {
  1791.   if (parsed_label
  1792.       && (parsed_label->analyze() & expression::CONTAINS_AT)
  1793.       && sort_fields.length() >= 2
  1794.       && sort_fields[0] == 'A'
  1795.       && sort_fields[1] == '+')
  1796.     consider_authors(v, v + n, 0);
  1797.   for (int i = 0; i < n; i++)
  1798.     v[i]->compute_label();
  1799. }
  1800.  
  1801.  
  1802. /* A reference with a list of authors <A0,A1,...,AN> _needs_ author i
  1803. where 0 <= i <= N if there exists a reference with a list of authors
  1804. <B0,B1,...,BM> such that <A0,A1,...,AN> != <B0,B1,...,BM> and M >= i
  1805. and Aj = Bj for 0 <= j < i. In this case if we can't say ``A0,
  1806. A1,...,A(i-1) et al'' because this would match both <A0,A1,...,AN> and
  1807. <B0,B1,...,BM>.  If a reference needs author i we only have to call
  1808. need_author(j) for some j >= i such that the reference also needs
  1809. author j. */
  1810.  
  1811. /* This function handles 2 tasks:
  1812. determine which authors are needed (cannot be elided with et al.);
  1813. determine which authors can have only last names in the labels.
  1814.  
  1815. References >= start and < end have the same first i author names.
  1816. Also they're sorted by A+. */
  1817.  
  1818. static void consider_authors(reference **start, reference **end, int i)
  1819. {
  1820.   if (start >= end)
  1821.     return;
  1822.   reference **p = start;
  1823.   if (i >= (*p)->get_nauthors()) {
  1824.     for (++p; p < end && i >= (*p)->get_nauthors(); p++)
  1825.       ;
  1826.     if (p < end && i > 0) {
  1827.       // If we have an author list <A B C> and an author list <A B C D>,
  1828.       // then both lists need C.
  1829.       for (reference **q = start; q < end; q++)
  1830.     (*q)->need_author(i - 1);
  1831.     }
  1832.     start = p;
  1833.   }
  1834.   while (p < end) {
  1835.     reference **last_name_start = p;
  1836.     reference **name_start = p;
  1837.     for (++p;
  1838.      p < end && i < (*p)->get_nauthors()
  1839.      && same_author_last_name(**last_name_start, **p, i);
  1840.      p++) {
  1841.       if (!same_author_name(**name_start, **p, i)) {
  1842.     consider_authors(name_start, p, i + 1);
  1843.     name_start = p;
  1844.       }
  1845.     }
  1846.     consider_authors(name_start, p, i + 1);
  1847.     if (last_name_start == name_start) {
  1848.       for (reference **q = last_name_start; q < p; q++)
  1849.     (*q)->set_last_name_unambiguous(i);
  1850.     }
  1851.     // If we have an author list <A B C D> and <A B C E>, then the lists
  1852.     // need author D and E respectively.
  1853.     if (name_start > start || p < end) {
  1854.       for (reference **q = last_name_start; q < p; q++)
  1855.     (*q)->need_author(i);
  1856.     }
  1857.   }
  1858. }
  1859.  
  1860. int same_author_last_name(const reference &r1, const reference &r2, int n)
  1861. {
  1862.   const char *ae1;
  1863.   const char *as1 = r1.get_sort_field(0, n, 0, &ae1);
  1864.   assert(as1 != 0);
  1865.   const char *ae2;
  1866.   const char *as2 = r2.get_sort_field(0, n, 0, &ae2);
  1867.   assert(as2 != 0);
  1868.   return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
  1869. }
  1870.  
  1871. int same_author_name(const reference &r1, const reference &r2, int n)
  1872. {
  1873.   const char *ae1;
  1874.   const char *as1 = r1.get_sort_field(0, n, -1, &ae1);
  1875.   assert(as1 != 0);
  1876.   const char *ae2;
  1877.   const char *as2 = r2.get_sort_field(0, n, -1, &ae2);
  1878.   assert(as2 != 0);
  1879.   return ae1 - as1 == ae2 - as2 && memcmp(as1, as2, ae1 - as1) == 0;
  1880. }
  1881.  
  1882.  
  1883. void int_set::set(int i)
  1884. {
  1885.   assert(i >= 0);
  1886.   int bytei = i >> 3;
  1887.   if (bytei >= v.length()) {
  1888.     int old_length = v.length();
  1889.     v.set_length(bytei + 1);
  1890.     for (int j = old_length; j <= bytei; j++)
  1891.       v[j] = 0;
  1892.   }
  1893.   v[bytei] |= 1 << (i & 7);
  1894. }
  1895.  
  1896. int int_set::get(int i) const
  1897. {
  1898.   assert(i >= 0);
  1899.   int bytei = i >> 3;
  1900.   return bytei >= v.length() ? 0 : (v[bytei] & (1 << (i & 7))) != 0;
  1901. }
  1902.  
  1903. void reference::set_last_name_unambiguous(int i)
  1904. {
  1905.   last_name_unambiguous.set(i);
  1906. }
  1907.  
  1908. void reference::need_author(int n)
  1909. {
  1910.   if (n > last_needed_author)
  1911.     last_needed_author = n;
  1912. }
  1913.  
  1914. const char *reference::get_authors(const char **end) const
  1915. {
  1916.   if (!computed_authors) {
  1917.     ((reference *)this)->computed_authors = 1;
  1918.     string &result = ((reference *)this)->authors;
  1919.     int na = get_nauthors();
  1920.     result.clear();
  1921.     for (int i = 0; i < na; i++) {
  1922.       if (last_name_unambiguous.get(i)) {
  1923.     const char *e, *start = get_author_last_name(i, &e);
  1924.     assert(start != 0);
  1925.     result.append(start, e - start);
  1926.       }
  1927.       else {
  1928.     const char *e, *start = get_author(i, &e);
  1929.     assert(start != 0);
  1930.     result.append(start, e - start);
  1931.       }
  1932.       if (i == last_needed_author
  1933.       && et_al.length() > 0
  1934.       && et_al_min_elide > 0
  1935.       && last_needed_author + et_al_min_elide < na
  1936.       && na >= et_al_min_total) {
  1937.     result += et_al;
  1938.     break;
  1939.       }
  1940.       if (i < na - 1) {
  1941.     if (na == 2)
  1942.       result += join_authors_exactly_two;
  1943.     else if (i < na - 2)
  1944.       result += join_authors_default;
  1945.     else
  1946.       result += join_authors_last_two;
  1947.       }
  1948.     }
  1949.   }
  1950.   const char *start = authors.contents();
  1951.   *end = start + authors.length();
  1952.   return start;
  1953. }
  1954.  
  1955. int reference::get_nauthors() const
  1956. {
  1957.   if (nauthors < 0) {
  1958.     const char *dummy;
  1959.     for (int na = 0; get_author(na, &dummy) != 0; na++)
  1960.       ;
  1961.     ((reference *)this)->nauthors = na;
  1962.   }
  1963.   return nauthors;
  1964. }
  1965.